#include "StdAfx.h"
#include "Triangle.h"
#include "Renderer.h"

CTriangle::CTriangle(void)
{
}


CTriangle::~CTriangle(void)
{
}

void CTriangle::Rasterize(CRenderer* pRenderer)
{
	vector<CVector4>& vColors = pRenderer->GetColors();
	vector<CVector4>& vWorldPositions = pRenderer->GetWorldPositions();
	vector<CVector4>& vTransformedPositions = pRenderer->GetTransformedPositions();
	vector<CVector4>& vNormals = pRenderer->GetNormals();
	vector<CVector4>& vTextureUVs = pRenderer->GetTextureUVs();

	DATA_TYPE x0 = m_vertex[0].transformedPosition.x;
	DATA_TYPE y0 = m_vertex[0].transformedPosition.y;
	DATA_TYPE x1 = m_vertex[1].transformedPosition.x;
	DATA_TYPE y1 = m_vertex[1].transformedPosition.y;
	DATA_TYPE x2 = m_vertex[2].transformedPosition.x;
	DATA_TYPE y2 = m_vertex[2].transformedPosition.y;

	// the simplest & robest algorithm
	int iMinX = __max(0, (int)ceilf(__min(x0, __min(x1, x2))));
	int iMinY = __max(0, (int)ceilf(__min(y0, __min(y1, y2))));
	int iMaxX = __min(WINDOW_WIDTH - 1, (int)floorf(__max(x0, __max(x1, x2))));
	int iMaxY = __min(WINDOW_HEIGHT - 1, (int)floorf(__max(y0, __max(y1, y2))));

	// for barycentric coordinate
	DATA_TYPE f12 = (y1 - y2) * x0 + (x2 - x1) * y0 + (x1 * y2 - x2 * y1);
	DATA_TYPE f20 = (y2 - y0) * x1 + (x0 - x2) * y1 + (x2 * y0 - x0 * y2);
	DATA_TYPE f01 = (y0 - y1) * x2 + (x1 - x0) * y2 + (x0 * y1 - x1 * y0);

	for (int y = iMinY; y <= iMaxY; ++y)
	{
		for (int x = iMinX; x <= iMaxX; ++x)
		{
			DATA_TYPE a = ((y1 - y2) * x + (x2 - x1) * y + (x1 * y2 - x2 * y1)) / f12;
			if (a < -EPSILON || a > 1.f + EPSILON)
				continue;
			DATA_TYPE b = ((y2 - y0) * x + (x0 - x2) * y + (x2 * y0 - x0 * y2)) / f20;
			if (b < -EPSILON || b > 1.f + EPSILON)
				continue;
			DATA_TYPE c = 1.f - a - b;
			if (c < -EPSILON || c > 1.f + EPSILON)
				continue;

			int idx = (int)x + (int)y * WINDOW_WIDTH;

			CVector4 vTransformedPosition = CVector4::Interpolate(a, b, c, m_vertex[0].transformedPosition, m_vertex[1].transformedPosition, m_vertex[2].transformedPosition);
			if (pRenderer->ZTest(idx, vTransformedPosition.z))
			{
				vTransformedPositions.at(idx) = vTransformedPosition;
				vWorldPositions.at(idx) = CVector4::Interpolate(a, b, c, m_vertex[0].worldPosition, m_vertex[1].worldPosition, m_vertex[2].worldPosition);
				vColors.at(idx) = CVector4::Interpolate(a, b, c, m_vertex[0].color, m_vertex[1].color, m_vertex[2].color);
				vNormals.at(idx) = CVector4::Interpolate(a, b, c, m_vertex[0].normal, m_vertex[1].normal, m_vertex[2].normal);
				vTextureUVs.at(idx) = CVector4::Interpolate(a, b, c, m_vertex[0].texCoord, m_vertex[1].texCoord, m_vertex[2].texCoord);
			}
		}
	}
}

void CTriangle::Transform(const CMatrix4& matTransform)
{
	for (int i = 0; i < 3; ++i)
	{
		m_vertex[i].transformedPosition = matTransform * m_vertex[i].worldPosition;
		for (int j = 0; j < 3; ++j)
			m_vertex[i].transformedPosition[j] /= m_vertex[i].transformedPosition[3];
		m_vertex[i].transformedPosition[3] = 1.f;
	}
}
